package com.wxzz.elearing.pay.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import com.wxzz.elearing.pay.entity.PayLog;
import com.wxzz.elearing.pay.entity.UserOrder;
import com.wxzz.elearing.pay.entity.UserTransaction;
import com.wxzz.elearing.pay.entity.UserWallet;
import com.wxzz.elearing.pay.mapper.PayLogMapper;
import com.wxzz.elearing.pay.mapper.UserOrderMapper;
import com.wxzz.elearing.pay.mapper.UserTransactionMapper;
import com.wxzz.elearing.pay.service.IUserTransactionService;
import com.wxzz.elearing.pay.service.IUserWalletService;
import com.wxzz.elearing.pay.service.openfeign.ICurriculumApiFeign;
import com.wxzz.elearing.pay.service.openfeign.IObsApiFeign;
import com.wxzz.elearing.pay.wx.mini.MD5Util;
import com.wxzz.elearing.pay.wx.pc.WXPayConfigImpl;
import com.wxzz.elearning.common.constants.OrderConstants;
import com.wxzz.elearning.common.utils.OpenFeignUtil;
import com.wxzz.elearning.common.utils.QRCodeUtil;
import com.wxzz.elearning.common.utils.YmlUtil;
import com.wxzz.elearning.common.vo.ReturnVO;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.rmi.ServerException;
import java.time.LocalDateTime;
import java.util.*;

/**
 * pc端微信支付
 */
@Service
public class WxPayServiceSingle {

    private final static Logger logger = LoggerFactory.getLogger(WxPayServiceSingle.class);

    //========================================pc端微信支付=======================================================
    private WXPay wxpay;
    private WXPayConfigImpl config;
    // private static WxPayServiceSingle wxPayService;

    public WxPayServiceSingle() {
        config = new WXPayConfigImpl();
        wxpay = new WXPay(config);
    }

//    public static WxPayServiceSingle getInstance() {
//        if (wxPayService == null) {
//            synchronized (WXPayConfigImpl.class) {
//                if (wxPayService == null) {
//                    wxPayService = new WxPayServiceSingle();
//                }
//            }
//        }
//        return wxPayService;
//    }

    @Autowired
    private IObsApiFeign obsApiFeign;

    @Autowired
    private UserOrderMapper userOrderMapper;


    @Autowired
    private PayLogMapper payLogMapper;

    /**
     * 微信下单接口
     *
     * @param //out_trade_no 订单号
     * @param //body         商家商品名
     * @param //money        总金额
     * @param //applyNo      商品编号
     * @return
     */
    public Map<String, String> doUnifiedOrder(Map<String, String> data) {
        //data.put("body", body);
        //data.put("out_trade_no", out_trade_no);
        data.put("device_info", "web");
        data.put("fee_type", "CNY");
        //data.put("total_fee", amt.substring(0, amt.lastIndexOf(".")));
        data.put("spbill_create_ip", "127.0.0.1");
        data.put("notify_url", YmlUtil.getBootstrapYml("pay.wx.pc-return-url").toString());
        data.put("trade_type", "NATIVE");
        //data.put("product_id", applyNo);
        //data.put("time_expire", "20170112104120");
        try {
            Map<String, String> r = wxpay.unifiedOrder(data);
            ReturnVO<String> stringReturnVO = obsApiFeign.makePayImage(r);
            JSONObject image = OpenFeignUtil.getJSONObject(stringReturnVO);
            Map<String, String> returnMap = new HashMap<>();
            returnMap.put("payUrl", image.getString("url"));
            //=======================生成订单=================================
            UserOrder userOrder = new UserOrder();
            userOrder.setEnterpriseId(Long.valueOf(data.get("enterpriseId")));
            userOrder.setUserId(Long.valueOf(data.get("adminUserId")));
            userOrder.setBusinessId(Long.valueOf(data.get("curriculumId")));
            userOrder.setUserType(Integer.valueOf(data.get("userType")));
            userOrder.setPayName(data.get("username"));
            userOrder.setPhone(data.get("phone"));
            userOrder.setIncomePrice(new BigDecimal(data.get("payMoney")));
            userOrder.setOrderNum(data.get("out_trade_no"));
            userOrder.setOrderTitle(data.get("orderTitle"));
            userOrder.setPayType(OrderConstants.PAY_TYPE_WX_PC);
            userOrder.setModelType(Integer.valueOf(data.get("modelType")));
            userOrderMapper.insert(userOrder);
            returnMap.put("orderId", userOrder.getId().toString());
            //==================支付日志================================
            PayLog payLog = new PayLog();
            payLog.setPayInfo(String.valueOf(data));
            payLog.setOrderNum(data.get("out_trade_no"));
            payLogMapper.insert(payLog);
            return returnMap;
        } catch (Exception e) {
            e.printStackTrace();
            logger.info(e.getMessage());
        }
        return null;
    }

    @Autowired
    private ICurriculumApiFeign curriculumApiFeign;

    @Autowired
    private IUserWalletService userWalletService;

    @Autowired
    private UserTransactionMapper userTransactionMapper;

    public Map<String, String> notifyUrlPc(HttpServletRequest request, HttpServletResponse response) throws Exception {
        logger.info("用户支付成功,回调！");
        String inputLine;
        String notityXml = "";
        try {
            request.setCharacterEncoding("UTF-8");
            // 微信给返回的东西
            while ((inputLine = request.getReader().readLine()) != null) {
                notityXml += inputLine;
            }
            request.getReader().close();
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("xml获取失败");
        }
        if (StringUtils.isEmpty(notityXml)) {
            logger.info("xml为空");
        }
        if (!checkSign(notityXml)) {
            logger.error("验签失败:[{}]", notityXml);
            throw new RuntimeException("验签失败");
        }
        logger.info("xml的值为：" + notityXml);
        Map<String, String> xmlMap = WXPayUtil.xmlToMap(notityXml); // 解析成map
        String json = JSON.toJSONString(xmlMap); // map 转成json
        logger.info(json);
        JSONObject jsonObject = JSONObject.parseObject(json);
        if ("SUCCESS".equals(jsonObject.getString("result_code")) && jsonObject.getString("result_code") != null
                && !jsonObject.getString("result_code").isEmpty()) {
            //double fee = jsonObject.getDoubleValue("total_fee");
            //returnPay.setTotal_fee(String.valueOf(fee / 100));
            logger.info("微信的支付状态为SUCCESS");
            // 支付成功业务
            synchronized (WxPayServiceSingle.class) { // 加入同步锁
                Thread.sleep(1000); //睡一秒,防止并发倒致数据不一致
//				addServiceCount(returnPay,response); // 写你支付成功后的业务, 比如给用户充值服务次数
                String orderNum = jsonObject.getString("out_trade_no");
                //==================支付日志================================
                PayLog payLog = payLogMapper.selectOne(new LambdaQueryWrapper<PayLog>()
                        .eq(PayLog::getOrderNum, orderNum));
                payLog.setNotifyInfo(notityXml);
                payLog.setNotifyTime(LocalDateTime.now());
                payLogMapper.updateById(payLog);

                UserOrder userOrder = userOrderMapper.selectOne(new LambdaQueryWrapper<UserOrder>()
                        .eq(UserOrder::getOrderNum, orderNum));
                if (userOrder == null) {
                    logger.error("订单编号[{}]的订单不存在", orderNum);
                    return null;
                }
                //修改订单状态为已支付
                userOrder.setPayTime(LocalDateTime.now());
                userOrder.setOrderStatus(1);
                userOrderMapper.updateById(userOrder);
                //拷贝课程数据
                curriculumApiFeign.copyNewCurriculum(userOrder.getEnterpriseId(), userOrder.getBusinessId(), userOrder.getId());
                //查询课程对应的企业
                ReturnVO<JSONObject> jsonObjectReturnVO = curriculumApiFeign.selectCurriculum4EnterpriseByOrderId(userOrder.getId());
                if (!"200".equals(jsonObjectReturnVO.getCode())) {
                    logger.error("课程模块支付查询课程信息失败,对应订单id[{}],返回对象[{}]", userOrder.getId(), jsonObjectReturnVO.toString());
                    return null;
                }
                JSONObject data = jsonObjectReturnVO.getData();
                //企业课程的收益
                //if (data.getInteger("curriculumType")==1){
                if (data.getLong("enterpriseId") != 0) {
                    UserTransaction userTransaction = new UserTransaction();
                    userTransaction.setMoney(userOrder.getIncomePrice());
                    UserWallet userWallet = userWalletService.updateUserWallet(data.getLong("enterpriseId"), 1, userOrder.getIncomePrice());
                    userTransaction.setBalance(userWallet.getUserBalance());
                    userTransaction.setDescription("用户购买企业课程");
                    userTransaction.setBusinessRemark("订单编号:" + userOrder.getOrderNum());
                    userTransaction.setUserType(1);
                    userTransaction.setType(0);
                    userTransaction.setUserId(data.getLong("enterpriseId"));
                    userTransaction.setUsername(userTransactionService.getUserName(1, data.getLong("enterpriseId")));
                    userTransaction.setTransactionStatus("存入余额");
                    userTransaction.setChangeType("企业购买课程");
                    userTransactionMapper.insert(userTransaction);
                }
                //==================支付日志================================
                payLog.setLogType(1);
                payLogMapper.updateById(payLog);
                //告诉微信不用重复通知
                String xml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/xml; charset=utf-8");
                PrintWriter out = response.getWriter();
                out.print(xml);
                out.close();
            }
            // 返回false的原因有可能是：订单已完成支付,或者订单已退款
        }
        return null;
    }

    @Autowired
    private IUserTransactionService userTransactionService;

    /**
     * 微信验签接口
     *
     * @return
     * @throws DocumentException
     */
    public boolean checkSign(String strXML) throws DocumentException {
        SortedMap<String, String> smap = new TreeMap<String, String>();
        Document doc = DocumentHelper.parseText(strXML);
        Element root = doc.getRootElement();
        for (Iterator iterator = root.elementIterator(); iterator.hasNext(); ) {
            Element e = (Element) iterator.next();
            smap.put(e.getName(), e.getText());
        }
        return isWechatSign(smap, config.getKey());
    }


    private boolean isWechatSign(SortedMap<String, String> smap, String apiKey) {
        StringBuffer sb = new StringBuffer();
        Set<Map.Entry<String, String>> es = smap.entrySet();
        Iterator<Map.Entry<String, String>> it = es.iterator();
        while (it.hasNext()) {
            Map.Entry<String, String> entry = it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (!"sign".equals(k) && null != v && !"".equals(v) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + apiKey);
        /** 验证的签名 */
        String sign = MD5Util.MD5Encode(sb.toString(), "utf-8").toUpperCase();
        /** 微信端返回的合法签名 */
        String validSign = ((String) smap.get("sign")).toUpperCase();
        return validSign.equals(sign);
    }
//
//    public static void main(String[] args) throws Exception {
//        WxPayServiceSingle wxPayServiceSingle = WxPayServiceSingle.getInstance();
//        String ss = wxPayServiceSingle.doUnifiedOrder("321", "名字", 1.00, "321");
//        System.out.println(ss);
//        // 存放在二维码中的内容
//        // 嵌入二维码的图片路径
//        String imgPath = null;
//        // 生成的二维码的路径及名称
//        String destPath = "E:\\ss.jpg";
//        //生成二维码
//        QRCodeUtil.encode(ss, imgPath, destPath, true);
//        //解析二维码
//        String str = QRCodeUtil.decode(destPath);
//        //打印出解析出的内容
//        System.out.println(str);
//    }
}
